package com.mlx.mylogin.inter;

import com.mlx.mylogin.base.Configuration;
import com.mlx.mylogin.base.HttpSnapshot;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Set;
import java.util.UUID;


public abstract class AbstractLoginManager extends AbstractHttpSnapshotFilter implements LoginManager {

    // JWT配置类
    protected Configuration configuration;

    public AbstractLoginManager(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public HttpServletRequest getRequest() {
        return getHttpSnapshot().getRequest();
    }

    @Override
    public HttpServletResponse getResponse() {
        return getHttpSnapshot().getResponse();
    }

    @Override
    public HttpSession getSession() {
        return getHttpSnapshot().getSession();
    }

    @Override
    public String getServletPath() {
        return getHttpSnapshot().getServletPath();
    }

    @Override
    public Object getUser() {
        return getHttpSnapshot().getUser();
    }

    /**
     * 颁发令牌
     * @param user 用户
     *
     */
    public String issueToken(Object user){

        HttpSnapshot httpSnapshot = getHttpSnapshot();

        httpSnapshot.setUser(user);

        String token = generateToken(httpSnapshot.getRequest(), user);

        httpSnapshot.setToken(token);

        saveTokenIntoCookie(httpSnapshot.getResponse(), token);

        saveToken(httpSnapshot.getRequest(), httpSnapshot.getResponse(), user, token);

        return token;
    }


    /**
     * 生成token令牌：调用issueToken()方法之后
     *
     * @param request 请求体
     * @param user 用户信息
     * @return token令牌
     */
    protected String generateToken(HttpServletRequest request, Object user){
        return UUID.randomUUID().toString().toUpperCase();
    }

    /**
     *
     * 保存token令牌进入cookie
     *
     * @param response 响应体
     * @param token 令牌信息
     *
     */
    private void saveTokenIntoCookie(HttpServletResponse response, String token){
        Cookie cookie = new Cookie(configuration.getTokenKey(), token);
        cookie.setMaxAge(Integer.MAX_VALUE);
        response.addCookie(cookie);
    }

    /**
     * 保存token令牌
     *
     * @param request 请求体
     * @param response 响应体
     * @param user 用户信息
     * @param token 令牌信息
     *
     */
    protected void saveToken(HttpServletRequest request, HttpServletResponse response, Object user, String token){
    }




    @Override
    protected void supplementUserData(HttpSnapshot httpSnapshot) {

        // 设置开放路径状态
        boolean openServletPath = checkOpenServletPath(httpSnapshot.getServletPath());

        httpSnapshot.setOpenServletPath(openServletPath);

        if (!openServletPath){

            identityAuthentication(httpSnapshot);
        }

    }

    /**
     * 判断是否是开放的请求地址
     */
    private boolean checkOpenServletPath(String servletPath){

        if (configuration.getOpenServletPathCollection() != null){
            for (String openServletPath : configuration.getOpenServletPathCollection()) {
                if (servletPath.equals(openServletPath)){
                    return true;
                }
            }
        }

        if (configuration.getOpenServletPathPrefixCollection() != null){
            for (String openServletPathPrefix : configuration.getOpenServletPathPrefixCollection()){
                if (servletPath.startsWith(openServletPathPrefix)){
                    return true;
                }
            }
        }

        if (configuration.getOpenServletPathSuffixCollection() != null){
            for (String openServletPathSuffix : configuration.getOpenServletPathSuffixCollection()){
                if (servletPath.endsWith(openServletPathSuffix)){
                    return true;
                }
            }
        }

        return false;
    }

    @Override
    public void identityAuthentication(HttpSnapshot httpSnapshot) {

        HttpServletRequest request = httpSnapshot.getRequest();

        String token = extractToken(request);

        httpSnapshot.setToken(token);

        Object user = parseToken(request, token);

        httpSnapshot.setUser(user);

        refreshToken(httpSnapshot);

    }

    /**
     * 提取token信息
     * @param request 请求体
     */
    protected String extractToken(HttpServletRequest request){
        String token = request.getHeader(configuration.getTokenKey());
        if (token != null){
            return token;
        }

        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies){
            if (configuration.getTokenKey().equals(cookie.getName())){
                return cookie.getValue();
            }
        }
        return null;
    }

    /**
     * 解析token：也可以理解为通过token获取用户信息
     * @param request 请求体
     * @param token 令牌
     * @return 用户对象
     */
    protected abstract Object parseToken(HttpServletRequest request, String token);



    /**
     * 刷新token，一般用于刷新过期时间
     *
     * @param httpSnapshot http快照
     */
    protected void refreshToken(HttpSnapshot httpSnapshot){
    }


    @Override
    public void removeToken() {
        HttpSnapshot httpSnapshot = getHttpSnapshot();
        removeCookieToken(httpSnapshot);
        removeToken(httpSnapshot);
    }

    /**
     * 移除cookie中的令牌信息
     *
     * @param snapshot http快照
     */
    private void removeCookieToken(HttpSnapshot snapshot){
        HttpServletRequest request = snapshot.getRequest();
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies){
            if (configuration.getTokenKey().equals(cookie.getName())){
                cookie.setMaxAge(0);
                HttpServletResponse response = snapshot.getResponse();
                response.addCookie(cookie);
            }
        }
    }

    /**
     *
     * 保存token令牌
     *
     * @param snapshot http快照
     */
    protected void removeToken(HttpSnapshot snapshot){
    }

}
